# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jhkim

import functools

from coin.exchange.base.tick import FixedTickPrice
from coin.exchange.bitfinex_v2.kr_rest.product import BitfinexProduct
from coin.exchange.bithumb.kr_rest.product import BithumbProduct
from coin.exchange.bitflyer_v1.kr_rest.futures_product import BitflyerFuturesProduct
from coin.exchange.bitmex.kr_rest.futures_product import BitmexFuturesProduct
from coin.exchange.upbit_v1.kr_rest.product import UpbitProduct
from coin.exchange.kr_rest.product_holders import get_holder_from_product


def get_price_krw(ccy):
  if ccy in ["BCHABC", "BCH"]:
    return 210000
  elif ccy in ["BCHSV", "BSV"]:
    return 150000
  elif ccy in ["BTC"]:
    return 7000000
  elif ccy in ["ETH"]:
    return 160000
  elif ccy in ["LTC"]:
    return 41000
  elif ccy in ["LINK"]:
    return 2700
  elif ccy in ["EOS"]:
    return 2500
  elif ccy in ["ETC"]:
    return 5000
  elif ccy in ["XRP"]:
    return 189
  elif ccy in ["XLM"]:
    return 80
  elif ccy in ["ADA"]:
    return 70
  elif ccy in ["TRX"]:
    return 20
  elif ccy in ["KRW"]:
    return 1
  elif ccy in ["USD", "USDT"]:
    return 1160
  else:
    raise ValueError(ccy)


def get_price(product):
  return get_price_krw(product.base.currency) / get_price_krw(product.quote.currency)


def get_tick_size(product):
  holder = get_holder_from_product(product)
  return holder.get_tick()


def get_target_tick_size(product):
  holder = get_holder_from_product(product)
  tick = holder.get_tick()
  if isinstance(tick, FixedTickPrice):
    return tick.tick_size
  price = get_price(product)
  next_price = tick.get_next_price(price)
  prev_price = tick.get_prev_price(next_price)
  return next_price - prev_price


class FeedManager(object):
  def __init__(self, on_book_callback, on_trade_callback, aggregation_map, feedspec):
    self._on_book_callback = on_book_callback
    self._on_trade_callback = on_trade_callback
    self._aggregation_map = aggregation_map
    self._feedspec = feedspec
    self.subscribed = {}

  def set_book_reset(self, products, book_builder_name, book_builder):
    for product in products:
      subscription_key = self._feedspec.get_subscription_key(product)
      if book_builder_name == subscription_key:
        if (product, book_builder_name) not in self.subscribed:
          self.subscribed[(product, book_builder_name)] = True
        else:
          continue
        if product.exchange in [
            'Bitmex', 'Okex', 'Bithumb', 'Upbit', 'Binance', 'Huobi', 'Bitfinex'
        ]:
          book_builder.subscribe(product, functools.partial(self.on_book, product))
        elif (product.exchange in ['Okex'] and product.product_type == 'Futures'
              and product.base in ['EOS', 'XRP']):
          book_builder.subscribe(product, functools.partial(self.on_book, product))
        elif self._aggregation_map.get(product, None):
          assert hasattr(book_builder, "subscribe_aggregated_book")
          tsize = self._aggregation_map[product]
          book_builder.subscribe_aggregated_book(
              product, [tsize], functools.partial(self.on_agg_book, product, tsize))
        else:
          book_builder.subscribe(product, functools.partial(self.on_book, product))

        if hasattr(book_builder, "subscribe_trade"):
          book_builder.subscribe_trade(product, functools.partial(self.on_trade, product))

  def on_book(self, product, book):
    self._on_book_callback(product, book)

  def on_agg_book(self, product, tsize, book):
    self._on_book_callback(product, book.get_aggregated_book(tsize))

  def on_trade(self, product, trade):
    self._on_trade_callback(product, trade)
